<template>
    <div class="pe-input-number" :class="[`pe-input-number-${size}`]"
        :style="{ '--pe-input-number-hover-border-color': disabled ? 'var(--pe-color-border)' : '' }">
        <div v-if="controlsPosition === 'default' && controls" class="pe-input-number-icon pe-input-number-left"
            :class="[reduceFlag ? 'pe-input-number-disabled' : '']" @click="reduce">
            <i v-if="!reduceIcon" class="pe-icon">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                    <path fill="currentColor" d="M128 544h768a32 32 0 1 0 0-64H128a32 32 0 0 0 0 64"></path>
                </svg>
            </i>
            <reduceIcon v-else class="pe-icon" />
        </div>
        <div class="pe-input-number-wapper">
            <input type="number" class="pe-input-number-inner"
                :style="{ '--pe-input-number-border-color': borderColor }" v-model="value" :placeholder="placeholder"
                :disabled="disabled" :min="min" :max="max" :readonly="readonly" @blur="blur" @focus="focus"
                @change="change" @input="input">
            <div v-if="controlsPosition === 'right' && controls" class="pe-input-number-position">
                <div class="pe-input-number-position-icon" :class="[addFlag ? 'pe-input-number-disabled' : '']"
                    @click="add">
                    <i v-if="!addIcon" class="pe-icon">
                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                            <path fill="currentColor"
                                d="m488.832 344.32-339.84 356.672a32 32 0 0 0 0 44.16l.384.384a29.44 29.44 0 0 0 42.688 0l320-335.872 319.872 335.872a29.44 29.44 0 0 0 42.688 0l.384-.384a32 32 0 0 0 0-44.16L535.168 344.32a32 32 0 0 0-46.336 0">
                            </path>
                        </svg>
                    </i>
                    <addIcon v-else class="pe-icon" />
                </div>
                <div class="pe-input-number-position-icon" :class="[reduceFlag ? 'pe-input-number-disabled' : '']"
                    @click="reduce">
                    <i v-if="!reduceIcon" class="pe-icon">
                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                            <path fill="currentColor"
                                d="M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.712a29.12 29.12 0 0 0 0-41.728 30.592 30.592 0 0 0-42.752 0z">
                            </path>
                        </svg>
                    </i>
                    <reduceIcon v-else class="pe-icon" />
                </div>
            </div>
        </div>
        <div v-if="controlsPosition === 'default' && controls" class="pe-input-number-icon pe-input-number-right"
            :class="[addFlag ? 'pe-input-number-disabled' : '']" @click="add">
            <i v-if="!addIcon" class="pe-icon">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                    <path fill="currentColor"
                        d="M480 480V128a32 32 0 0 1 64 0v352h352a32 32 0 1 1 0 64H544v352a32 32 0 1 1-64 0V544H128a32 32 0 0 1 0-64z">
                    </path>
                </svg>
            </i>
            <addIcon v-else class="pe-icon" />
        </div>
        <div v-if="disabled" class="pe-disabled"></div>
    </div>
</template>

<script setup lang="ts">
import { Component, ref, watch } from "vue"


/**
 * @param min 设置计数器允许的最小值
 * @param max 设置计数器允许的最大值
 * @param step 计数器步长
 * @param size 计数器尺寸
 * @param readonly 原生 readonly 属性，是否只读
 * @param disabled 是否禁用状态
 * @param placeholder 等价于原生 input placeholder 属性
 * @param controls-position 控制按钮位置
 * @param controls 是否使用控制按钮
 * @param name 等价于原生 input name 属性
 * @param reduce-icon 自定义输入框按钮减少图标
 * @param add-icon 	自定义输入框按钮增加图标
 */
interface Props {
    min?: number,
    max?: number,
    step?: number,
    size?: 'default' | 'large' | 'small',
    readonly?: boolean,
    disabled?: boolean,
    placeholder?: string,
    controlsPosition?: 'default' | 'right',
    controls?: boolean,
    name?: string,
    reduceIcon?: Component,
    addIcon?: Component
}

const props = withDefaults(defineProps<Props>(), {
    step: 1,
    size: "default",
    readonly: false,
    disabled: false,
    controlsPosition: "default",
    controls: true
})

/**
 * blur 当选择器的输入框失去焦点时触发
 * focus 当选择器的输入框获得焦点时触发
 * change 仅当 modelValue 改变时，当输入框失去焦点或用户按Enter时触发
 * input 在 Input 值改变时触发
 */
const emits = defineEmits(["blur", "focus", "change", "input"])

const value = defineModel({ type: Number, default: 0 })

// 获取焦点事件
const borderColor = ref<string>("")
const focus = () => {
    borderColor.value = "var(--pe-color-primary)"
}

// 失去焦点事件
const blur = () => {
    if (props.min !== undefined && value.value < props.min) {
        value.value = props.min
    }
    if (props.max !== undefined && value.value > props.max) {
        value.value = props.max
    }
    emits("blur")
}

// 仅当 modelValue 改变时，当输入框失去焦点或用户按Enter时触发
const change = () => {
    emits("change", value.value)
}

// 在 Input 值改变时触发
const input = () => {
    emits("input", value.value)
}

// 减
const reduceFlag = ref<boolean>(false)
const reduce = () => {
    if (props.min !== undefined) {
        if (value.value - props.step >= props.min) {
            value.value -= props.step
            emits("change", value.value)
        }
    } else {
        value.value -= props.step
        emits("change", value.value)
    }
}

// 加
const addFlag = ref<boolean>(false)
const add = () => {
    if (props.max !== undefined) {
        if (value.value + props.step <= props.max) {
            value.value += props.step
            emits("change", value.value)
        }
    } else {
        value.value += props.step
        emits("change", value.value)
    }
}

watch(value, newValue => {
    if (props.min !== undefined) {
        reduceFlag.value = !(newValue - props.step >= props.min)
    }
    if (props.max !== undefined) {
        addFlag.value = !(value.value + props.step <= props.max)
    }
})

</script>

<script lang="ts">
export default {
    name: "pe-input-number"
}
</script>
